/*************************************************************************
                           Monitoring  -  description
                             -------------------
    début                : 28 janv. 2012
    copyright            : (C) 2012 par cristi
    e-mail               : 
*************************************************************************/

//---------- Réalisation de la tâche <Monitoring> (fichier Monitoring.c) ---

/////////////////////////////////////////////////////////////////  INCLUDE
//-------------------------------------------------------- Include système

//------------------------------------------------------ Include personnel
#include "Monitoring.h"
#include "config.h"

///////////////////////////////////////////////////////////////////  PRIVE
//------------------------------------------------------------- Constantes

//------------------------------------------------------------------ Types

//---------------------------------------------------- Variables statiques

//------------------------------------------------------ Fonctions privées

//////////////////////////////////////////////////////////////////  PUBLIC
//---------------------------------------------------- Fonctions publiques

// type nom_fonction(  )
// Mode d'emploi :
// Algorithme :
// Contrat :
//{
	
//} //----- fin de nom_fonction
void handler(int sig)
{
	msgctl(bal_monitoring_mere, IPC_RMID, NULL);
	msgctl(bal_mere_actionneur, IPC_RMID, NULL);

	exit(EXIT_SUCCESS);
}


int main()
// Mode d'emploi :
// Algorithme :
// Contrat :
{
	/* debut phase d'initialisation */
	int returnConnect;
	struct sockaddr_in serverAddr;
	char server[255];
	struct hostent *hostp;

	/* obtenir un descripteur de socket */
	if((socketClient = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("Client socket error!");
		exit(1);
	}
	else
	{
		printf("Client socket OK!\n");
	}

	strcpy(server, SERVER);

	memset(&serverAddr, 0x00, sizeof(struct sockaddr_in));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(SERVPORT);

	if((serverAddr.sin_addr.s_addr = inet_addr(server)) == (unsigned long)INADDR_NONE)
	{
		/* When passing the host name of the server as a */
		/* parameter to this program, use the gethostbyname() */
		/* function to retrieve the address of the host server. */

		/***************************************************/

		/* get host address */
		hostp = gethostbyname(server);

		if(hostp == (struct hostent *)NULL)
		{
			printf("HOST NOT FOUND --> ");
			/* h_errno is usually defined */
			/* in netdb.h */
			printf("h_errno = %d\n",h_errno);
			printf("---This is a client program---\n");
			close(socketClient);
			exit(-1);
		}
		memcpy(&serverAddr.sin_addr, hostp->h_addr, sizeof(serverAddr.sin_addr));
	}

	/* connect() to server. */
	if((returnConnect = connect(socketClient, (struct sockaddr *)&serverAddr, sizeof(serverAddr))) < 0)
	{
		perror("Client connect error!");
		close(socketClient);
		exit(-1);
	}
	else
	{
		printf("Connection établie:)\n");
	}


	//creation des boites aux lettres
	bal_monitoring_mere = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
	if (bal_monitoring_mere == -1) {
		perror("Problème pour obtenir la file capteurs");
		exit(1);
	}

	bal_mere_actionneur = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
	if (bal_mere_actionneur == -1) {
		perror("Problème pour obtenir la file actionneurs");
		exit(1);
	}

	signal(SIGTERM, handler);

	int etatCapteur = -1; //0 if it should be closed, 1 for open, -1 for not set

	//creation forks test
	pid_t pID = fork();
	if (pID == 0)                // child
	{
		// Code only executed by child process
		printf("debut phase test\n");
		int tailleMessage;
		MsgCapteur msg;

		for(;;)
		{
			tailleMessage = msgrcv(bal_monitoring_mere, &msg, sizeof(MsgCapteur) - sizeof(long), 0, IPC_NOWAIT);
			if(tailleMessage > 0)
			{
				printf("message received from network and through bal:::: capteur:%s; valeur:%f\n", msg.idCapteur, msg.valeur);
			}
			if(msg.type == 2)
			{
				switch((int)msg.valeur)
				{
				case 1:
					etatCapteur = 1;
					break;
				case 2:
					etatCapteur = 0;
					break;
				case 0:
					if(etatCapteur >= 0)
					{
						MsgActionneur msg;
						msg.type = 1;
						msg.onOff = etatCapteur;
						msgsnd(bal_mere_actionneur, &msg, sizeof(MsgActionneur) - sizeof(long), 0);
						printf("Message bien depose dans la boite aux lettres\n");
						etatCapteur = -1;
					}
					break;
				}
			}
		}
	}
	else if (pID < 0)            // failed to fork
	{
		printf("failed to fork");
		exit(1);
		// Throw exception
	}

	else                                   // parent
	{
		// Code only executed by parent process


		//creation tache reception

		pthread_t thread_reception;
		pthread_t thread_envoie;

		if ( pthread_create(&thread_envoie, NULL, tache_envoie, NULL) ){
			perror("Erreur lors de pthread_create -- tache_envoie\n");
			exit(-1);
		}

		if ( pthread_create(&thread_reception, NULL, tache_reception, NULL) ){
			perror("Erreur lors de pthread_create -- tache_reception\n");
			exit(-1);
		}
	}

	/* fin phase d'initialisation */

	/* debut phase moteur */
	char ch;
	for(;;)
	{
		ch = getchar();
		printf("read char is: %c\n", ch);

		if(ch == 'q')
		{
			printf("Exit process!Buh-bye!!");
			close(socketClient);
			exit(0);
		}
	}
	/* fin phase moteur */

	/* phase de destruction */
	/* Close socket descriptor from client side. */
	/*close(socketClient);

	exit(0);
*/
	return 0;

} //----- fin de main


void *tache_reception()
// Mode d'emploi : tache chargee de la reception des messages du socket
// Contrat :
{
	int totalcnt;
	char buffer[BUFFERSIZE];

	for(;;)
	{
		int res;
		fd_set readReady;
		struct timeval nowait;

		FD_ZERO(&readReady);
		FD_SET(socketClient, &readReady);
		memset((char*)&nowait, 0, sizeof(nowait));

		res = select(socketClient + 1, &readReady, NULL, NULL, &nowait);

		if(FD_ISSET(socketClient, &readReady))
		{
			totalcnt = 0;
			totalcnt = recv(socketClient, buffer, sizeof(buffer), 0);
			if (totalcnt == -1)
			{
				// traitement de l'erreur
				perror("Client-read() error");
				close(socketClient);
				exit(-1);
			}

			buffer[totalcnt] = '\0';

			//tache traitement
			pthread_t thread_traitement;
			if ( pthread_create(&thread_traitement, NULL, tache_traitement_capteurs, buffer) )
			{
				perror("Erreur lors de pthread_create -- tache_traitement_capteurs\n");
				exit(-1);
			}

			//get new message from thread
			int ret_th;
			void* ret;
			MsgCapteur* rez;
			ret_th = pthread_join(thread_traitement, &ret);
			if(ret_th != 0)
			{
				perror("Erreur lors de recuperation param tache_traitement_actionneurs\n");
				exit(-1);
			}
			rez = (MsgCapteur*)ret;

			if(rez->type != 0)
			{
				//deposer message dans la boite aux lettres
				msgsnd(bal_monitoring_mere, rez, sizeof(MsgCapteur) - sizeof(long), 0);
			}

			free(rez);
		}
	}

	free(buffer);

	return 0;
}

//function Cette fonction permet d'extraire une sous-chaîne de s comprise entre l'indice start et end.
char *str_sub (const char *s, unsigned int start, unsigned int end)
{
   char *new_s = NULL;

   if (s != NULL && start < end)
   {
/* (1)*/
      new_s = malloc (sizeof (*new_s) * (end - start + 2));
      if (new_s != NULL)
      {
         int i;

/* (2) */
         for (i = start; i <= end; i++)
         {
/* (3) */
            new_s[i-start] = s[i];
         }
         new_s[i-start] = '\0';
      }
      else
      {
         fprintf (stderr, "Memoire insuffisante\n");
         exit (EXIT_FAILURE);
      }
   }
   return new_s;
}

void *tache_traitement_capteurs(void* msg)
// Mode d'emploi : tache chargee du traitement des message
// 				recu des capteurs
// Contrat :
{
	MsgCapteur* newMsg = malloc(sizeof(MsgCapteur));
	char* messageBrut = (char *)msg;

	//printf("message avant traitement: %s\n", messageBrut);

	//decryptage du message
	char *sync_bytes = malloc (sizeof (*sync_bytes) * 4);
	char *h_SEQ_length= malloc(sizeof(*h_SEQ_length) * 2);
	char *org = malloc(sizeof(*org) * 2);
	char *data_bytes = malloc(sizeof(*data_bytes) * 8);
	char *id_bytes = malloc(sizeof(*id_bytes) * 8);
	char *status = malloc(sizeof(*status) * 2);
	char *check_sum = malloc(sizeof(*check_sum) * 2);


	/*sync_bytes = str_sub(messageBrut,0,3);
	printf("sync_bytes est : %s \n",sync_bytes);
	h_SEQ_length = str_sub(messageBrut,4,5);
	printf("h_SEQ-bytes est : %s \n",h_SEQ_length);
	org = str_sub(messageBrut,6,7);
	printf("org est : %s \n",org);*/
	data_bytes = str_sub(messageBrut,8,15);
	id_bytes = str_sub(messageBrut,16,23);
	status = str_sub(messageBrut,24,25);
	/*
	check_sum = str_sub(messageBrut,26,27);
	printf("check_sum %s \n",check_sum);*/

	newMsg->type = 0;

	if(!strcmp(id_bytes,"0021CC07")) 	//tester si c'est le capteur ID 0021CC07
	{
		strcpy(newMsg->idCapteur, id_bytes);

		newMsg->type = 2;

		switch((atoi)(data_bytes))
		{
		case 10000000:
			printf("bouton A1 \n ");
			newMsg->valeur = 1;
			break;
		case 30000000:
			printf("bouton A2 \n ");
			newMsg->valeur = 2;
			break;
		case 50000000:
			printf("bouton B1 \n ");
			newMsg->valeur = 3;
			break;
		case 70000000:
			printf("bouton B2 \n ");
			newMsg->valeur = 4;
			break;
		case 15000000:
			printf("bouton A1 et B1 \n ");
			newMsg->valeur = 5;
			break;
		case 17000000:
			printf("bouton A1 et B2 \n ");
			newMsg->valeur = 6;
			break;
		case 35000000:
			printf("bouton A2 et B1 \n ");
			newMsg->valeur = 7;
			break;
		case 37000000:
			printf("bouton A2 et B2 \n ");
			newMsg->valeur = 8;
			break;
		case 00000000:
			printf("bouton lache \n ");
			newMsg->valeur = 0;
			break;
		default:
			printf("data recu inconnu \n ");
			newMsg->valeur = -1;
			break;
		}
	}

	free(sync_bytes);
	free(h_SEQ_length);
	free(org);
	free(data_bytes);
	free(id_bytes);
	free(status);
	free(check_sum);

	pthread_exit(newMsg);
	return 0;
}

void *tache_envoie()
// Mode d'emploi : tache chargee de l'envoie des trames vers les capteurs
// Contrat :
{
	int totalcnt;
	int tailleMessage;
	MsgActionneur* msg = malloc(sizeof(MsgActionneur));

	while(1)
	{
		//wait for message in messagebox
		tailleMessage = msgrcv(bal_mere_actionneur, msg, sizeof(MsgActionneur) - sizeof(long), 0, IPC_NOWAIT);
		//TODO:DEBUG MSG RECUPERE
		//read message from messagebox
		if(tailleMessage >= 0)
		{
		//launch tache_traitement_actionneurs with read message
			pthread_t thread_traitement;
			if ( pthread_create(&thread_traitement, NULL, tache_traitement_actionneurs, (void*)msg) )
			{
				perror("Erreur lors de pthread_create -- tache_traitement_actionneurs\n");
				exit(-1);
			}
		//get new message from thread
			int ret_th;
			char* message;
			ret_th = pthread_join(thread_traitement, (void**)&message);
			if(ret_th != 0)
			{
				perror("Erreur lors de recuperation param tache_traitement_actionneurs\n");
				exit(-1);
			}
		//send over network

			totalcnt = 0;
			totalcnt = send(socketClient, message, strlen(message), 0);
			printf("taille du message envoye: %d\n", totalcnt);
			if (totalcnt == -1)
			{
				// traitement de l'erreur
				perror("Client-read() error");
				close(socketClient);
				exit(-1);
			}

			//TODO:DEBUG
			printf("message '%s' sent!\n", message);

			free(message);
		}
	}

	free(msg);

	return 0;
}

void *tache_traitement_actionneurs(void* msg)
// Mode d'emploi : tache chargee du traitement des messages
// 				a envoyer vers les actionneurs
// Contrat :
{
	MsgActionneur* m = (MsgActionneur*)msg;

	char* message = malloc(29);

	printf("read char is: :::::: %d", m->onOff);

	if(m->onOff == 0)
	{
		strcpy(message, "A55A6B0560000000FF9F1E0730C3");
	}
	else if(m->onOff == 1)
	{
		strcpy(message, "A55A6B0540000000FF9F1E0730A3");
	}
	else
	{
		strcpy(message, "-1");
	}

	pthread_exit(message);

	return 0;
}


